#pragma once
#include <stdlib.h>
#include <atomic>

 template<typename T>
 void SLT_EmbedSptr_defDeleter(T *_p)
{
	 delete (T*)(_p);
}

template <class T>
class SLT_EmbedSptrCounterBase
{
public:
	SLT_EmbedSptrCounterBase(void (*_deleter_fun)(T* _p) = SLT_EmbedSptr_defDeleter) :m_nCount(0) {
		m_deleter_fun = _deleter_fun;
	}
	virtual ~SLT_EmbedSptrCounterBase() {}
	
	inline void AddRef(){
		++m_nCount;
	}

	inline void Release(){
		if (0 == --m_nCount) {
			m_deleter_fun((T*)this);
		}
	}
	std::atomic<uint32_t>  m_nCount;
	void (*m_deleter_fun)(T* _p);
};

template<class object>
class SLT_EmbedSmartPtr
{
public:
	explicit SLT_EmbedSmartPtr(object* pObject){
		m_pObject = pObject;
		if ( m_pObject != NULL ){
			pObject->AddRef();	
		}
	}
	SLT_EmbedSmartPtr() {}
	SLT_EmbedSmartPtr(const SLT_EmbedSmartPtr<object> &GMSmartPtr){
		m_pObject = GMSmartPtr.get();
		if (m_pObject != NULL)	{
			m_pObject->AddRef();
		}
	}
	//
	~SLT_EmbedSmartPtr(){
		if( m_pObject != NULL )	{
			m_pObject->Release();
		}
	}

	SLT_EmbedSmartPtr& operator = (const SLT_EmbedSmartPtr<object>& GMSmartPtr)	{
		object * pTmpObject	= GMSmartPtr.get();
		if (pTmpObject != NULL)	{
			pTmpObject->AddRef();
		}
		if (m_pObject != NULL) 	{
			m_pObject->Release(); 
		}
		m_pObject = pTmpObject;
		return *this;
	}
	object& operator* (){return *(m_pObject);}
	object& operator* () const {	return *(m_pObject);}
	object* operator-> (){	return m_pObject;}
	object* operator-> () const {	return m_pObject;}
	bool operator== (const SLT_EmbedSmartPtr& GMSmartPtr) const {	return m_pObject == GMSmartPtr.get();}
	bool operator== (const object* pObject) const {	return m_pObject == pObject;}
	bool operator!= (const SLT_EmbedSmartPtr& GMSmartPtr) const {	return !(*this == GMSmartPtr);}
	bool operator!= (const object* pObject) const {	return !((*this).get() == pObject);	}
	operator bool() const{ return m_pObject?true:false; } 
	object* get(){	return m_pObject;}
	object* get() const	{return m_pObject;}
	void reset(object* pObject = nullptr)	{
		if(pObject != nullptr)	{
			pObject->AddRef();
		}
		if (m_pObject != nullptr) 	{
			m_pObject->Release();
			//m_pObject = NULL;
		}	
		m_pObject = pObject;		
	}
private:
	object * m_pObject = nullptr;
};
